{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## datetime\n",
    "### datetime是Python处理日期和时间的标准库\n",
    "\n",
    "获取当前日期和时间\n",
    "我们先看如何获取当前日期和时间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "now = datetime.now() # 获取当前datetime\n",
    "print(now)\n",
    "print('类型',type(now))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意到datetime是模块，datetime模块还包含一个datetime类，通过from datetime import datetime导入的才是datetime这个类。\n",
    "\n",
    "如果仅导入import datetime，则必须引用全名datetime.datetime。\n",
    "\n",
    "datetime.now()返回当前日期和时间，其类型是datetime"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 获取指定日期和时间\n",
    "要指定某个日期和时间，我们直接用参数构造一个datetime："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt = datetime(2016, 3, 14, 10, 20, 12,1123) # 用指定日期时间创建datetime\n",
    "print(dt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "datetime转换为timestamp\n",
    "\n",
    "在计算机中，时间实际上是用数字表示的。\n",
    "\n",
    "我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time，记为0（1970年以前的时间timestamp为负数），\n",
    "\n",
    "当前时间就是相对于epoch time的秒数，称为timestamp。\n",
    "\n",
    "timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00\n",
    "\n",
    "北京时间：\n",
    "timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00\n",
    "\n",
    "可见timestamp的值与时区毫无关系，因为timestamp一旦确定，其UTC时间就确定了，转换到任意时区的时间也是完全确定的，\n",
    "\n",
    "这就是为什么计算机存储的当前时间是以timestamp表示的，因为全球各地的计算机在任意时刻的timestamp都是完全相同的（假定时间已校准）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt.timestamp() # 把datetime转换为timestamp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意Python的timestamp是一个浮点数。如果有小数位，小数位表示毫秒数。\n",
    "\n",
    "某些编程语言（如Java和JavaScript）的timestamp使用整数表示毫秒数，这种情况下只需要把timestamp除以1000就得到Python的浮点表示方法\n",
    "\n",
    "\n",
    "### timestamp转换为datetime\n",
    "要把timestamp转换为datetime，使用datetime提供的fromtimestamp()方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = 1557942000.0\n",
    "print(datetime.fromtimestamp(t))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### str转换为datetime\n",
    "很多时候，用户输入的日期和时间是字符串，要处理日期和时间，\n",
    "\n",
    "首先必须把str转换为datetime。转换方法是通过datetime.strptime()实现，\n",
    "\n",
    "需要一个日期和时间的格式化字符串："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')\n",
    "print(cday)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "字符串'%Y-%m-%d %H:%M:%S'规定了日期和时间部分的格式。详细的说明请参考[Python](https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior)文档。\n",
    "\n",
    "注意转换后的datetime是没有时区信息的。\n",
    "\n",
    "\n",
    "### datetime转换为str\n",
    "如果已经有了datetime对象，要把它格式化为字符串显示给用户，就需要转换为str，\n",
    "\n",
    "转换方法是通过strftime()实现的，同样需要一个日期和时间的格式化字符串："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "now = datetime.now()\n",
    "print(now.strftime('%a, %b %d %H:%M'))\n",
    "print(now.strftime('%Y-%m-%d %H:%M:%S'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### datetime加减\n",
    "对日期和时间进行加减实际上就是把datetime往后或往前计算，得到新的datetime。加减可以直接用+和-运算符，不过需要导入timedelta这个类："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime, timedelta\n",
    "now = datetime.now()\n",
    "print(now)\n",
    "print(\"加10个小时\",now + timedelta(hours=3))\n",
    "print(\"加1天\",now + timedelta(days=1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## time \n",
    "python 出来时间的标准库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# time模块中，三种时间形式之间的转换\n",
    "time_stamp = time.time()                        # 时间戳\n",
    "local_time = time.localtime(time_stamp)         # 时间戳转struct_time类型的本地时间\n",
    "utc_time = time.gmtime(time_stamp)              # 时间戳转struct_time类型的utc时间\n",
    "print(\"本地时间\", local_time)\n",
    "print(\"utc时间\", utc_time)\n",
    "time_stamp_1 = time.mktime(local_time)          # struct_time类型的本地时间转时间戳\n",
    "print(\"时间戳的类型\",type(time_stamp), time_stamp, time_stamp_1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# time模块中，三种时间形式和字符串之间的转换\n",
    "print(time.ctime(time_stamp))           # 时间戳转字符串(本地时间字符串)\n",
    "\n",
    "print(time.asctime(local_time))         # struct_time类型的本地时间转字符串\n",
    "print(time.asctime(utc_time))           # struct_time类型的utc时间转字符串\n",
    "\n",
    "print(time.strftime(\"%Y-%m-%d, %H:%M:%S, %w\", local_time))      # struct_time类型的本地时间转字符串：自定义格式\n",
    "print(time.strftime(\"%Y-%m-%d, %H:%M:%S, %w\", utc_time))        # struct_time类型的utc时间转字符串：自定义格式\n",
    "\n",
    "struct_time = time.strptime(\"2016-11-15, 15:32:12, 2\", \"%Y-%m-%d, %H:%M:%S, %w\")       # 字符串转struct_time类型\n",
    "print(struct_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 练习：　求运行时间计算\n",
    "start = time.time()\n",
    "for i in range(3000):\n",
    "    pass\n",
    "end = ???\n",
    "during = ???\n",
    "print(\"运行时间为%f秒\" % during)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## base64\n",
    "Base64是一种用64个字符来表示任意二进制数据的方法。\n",
    "\n",
    "用记事本打开exe、jpg、pdf这些文件时，我们都会看到一大堆乱码，因为二进制文件包含很多无法显示和打印的字符，\n",
    "\n",
    "所以，如果要让记事本这样的文本处理软件能处理二进制数据，就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。\n",
    "\n",
    "Base64编码会把3字节的二进制数据编码为4字节的文本数据，长度增加33%，好处是编码后的文本数据可以在邮件正文、网页等直接显示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import base64\n",
    "# 编码\n",
    "base64.b64encode(b'binary\\x00string')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 解码\n",
    "base64.b64decode(b'YmluYXJ5AHN0cmluZw==')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "由于标准的Base64编码后可能出现字符+和/，在URL中就不能直接作为参数，所以又有一种\"url safe\"的base64编码，其实就是把字符+和/分别变成-和_："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"一般编码：\",base64.b64encode(b'i\\xb7\\x1d\\xfb\\xef\\xff'))\n",
    "print(\"url安全编码：\", base64.urlsafe_b64encode(b'i\\xb7\\x1d\\xfb\\xef\\xff'))\n",
    "print(\"解码：\",base64.urlsafe_b64decode('abcd--__'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](file/base64.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ls_f = None\n",
    "with open('file/base64.png','rb') as f: #二进制方式打开图文件\n",
    "    ls_f=base64.b64encode(f.read())\n",
    "\n",
    "print(ls_f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## itertools\n",
    "\n",
    "Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数。\n",
    "\n",
    "### 迭代器\n",
    "迭代是Python最强大的功能之一，是访问集合元素的一种方式。\n",
    "\n",
    "迭代器是一个可以记住遍历的位置的对象。\n",
    "\n",
    "迭代器对象从集合的第一个元素开始访问，直到所有的元素被访问完结束。迭代器只能往前不会后退。\n",
    "\n",
    "迭代器有两个基本的方法：iter() 和 next()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import itertools\n",
    "natuals = itertools.count(2) # 创建一个迭代对象从 2 开始，每次加 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"每次都不一样\",next(natuals))   #代码会打印出自然数序列，没有终点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cs = itertools.cycle('ABC') # 创建一个迭代对象，循环输出 A B C"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"循环输出\",next(cs)) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "！ 迭代对象，它不会事先把无限个元素生成出来，事实上也不可能在内存中创建无限多个元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "排列，可以重复\n",
      "('a', 'b')\n",
      "('a', 'c')\n",
      "('b', 'a')\n",
      "('b', 'c')\n",
      "('c', 'a')\n",
      "('c', 'b')\n",
      "组合\n",
      "('a', 'b')\n",
      "('a', 'c')\n",
      "('b', 'c')\n"
     ]
    }
   ],
   "source": [
    "# 排列组合\n",
    "print(\"排列，可以重复\")\n",
    "for m in  itertools.permutations('abc', 2):\n",
    "    print(m)\n",
    "print(\"组合\")\n",
    "for m in  itertools.combinations('abc', 2):\n",
    "    print(m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dir(itertools)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('a', 'b')\n",
      "('a', 'c')\n",
      "('b', 'c')\n"
     ]
    }
   ],
   "source": [
    "for m in itertools.combinations('abc', 2):\n",
    "    print(m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
